package cn.blnp.net.flowable.boot.config.flowable;

import cn.blnp.net.flowable.boot.config.flowable.listener.GlobalProcessCreateListener;
import cn.blnp.net.flowable.boot.config.flowable.listener.GlobalTaskCreateListener;
import cn.blnp.net.flowable.boot.customer.flowable.cache.FlowableSerializable;
import cn.blnp.net.flowable.boot.customer.flowable.handler.CusBusinessCalendar;
import cn.blnp.net.flowable.boot.customer.flowable.handler.TimeoutReminderJobHandler;
import cn.blnp.net.flowable.boot.customer.flowable.holder.MultiTenantInfoHolder;
import cn.blnp.net.flowable.boot.ext.manager.CustomAsyncHistoryManager;
import cn.blnp.net.flowable.boot.ext.manager.MongoHistoricPrecessInstanceDataManager;
import cn.blnp.net.flowable.boot.ext.manager.RocketMqMessageBasedJobManager;
import cn.blnp.net.flowable.boot.ext.producer.HistoricDataCompensationProducer;
import cn.hutool.core.collection.ListUtil;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.common.engine.impl.calendar.BusinessCalendar;
import org.flowable.common.engine.impl.calendar.MapBusinessCalendarManager;
import org.flowable.common.engine.impl.util.DefaultClockImpl;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.flowable.engine.impl.form.FormEngine;
import org.flowable.form.engine.configurator.FormEngineConfigurator;
import org.flowable.form.spring.SpringFormEngineConfiguration;
import org.flowable.job.service.impl.asyncexecutor.AsyncJobExecutorConfiguration;
import org.flowable.spring.ProcessEngineFactoryBean;
import org.flowable.spring.SpringProcessEngineConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.transaction.PlatformTransactionManager;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.util.*;

import static org.flowable.common.engine.api.delegate.event.FlowableEngineEventType.*;

/**
 * <h3>自定义配置注册</h3>
 *
 * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
 * @version 1.0
 * @since 2025/5/28 16:48
 */
@Slf4j
@Configuration
public class FlowableEngineConfiguration {

    @Resource
    private DataSource dataSource;
    @Resource
    private PlatformTransactionManager transactionManager;
    @Resource
    private MultiTenantDataSourceProcessConfig multiTenantDataSourceProcessConfig;
    @Resource
    private MultiTenantInfoHolder tenantInfoHolder;
    @Resource
    private MongoTemplate mongoTemplate;
    @Resource
    private HistoricDataCompensationProducer historicDataCompensationProducer;
    @Resource
    private GlobalProcessCreateListener processStartListener;
    @Resource
    private GlobalTaskCreateListener taskCreateListener;

    @Bean(name = "processEngine")
    @DependsOn("mapBusinessCalendarManager")
    public ProcessEngineFactoryBean processEngineFactoryBean(MapBusinessCalendarManager mapBusinessCalendarManager) {
        ProcessEngineFactoryBean factoryBean = new ProcessEngineFactoryBean();
        factoryBean.setProcessEngineConfiguration(processEngineConfiguration(mapBusinessCalendarManager));
        DefaultClockImpl  clock = new DefaultClockImpl();
        return factoryBean;
    }

    @Bean(name = "processEngineConfiguration")
    public ProcessEngineConfigurationImpl processEngineConfiguration(MapBusinessCalendarManager mapBusinessCalendarManager) {
        //flowableSerializable();
        //初始化工作流引擎配置
        SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration();
        //设置表单引擎链接的数据源
        configuration.setDataSource(dataSource);
        configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        //设置事务管理器
        configuration.setTransactionManager(transactionManager);
        //初始化表单引擎配置
        SpringFormEngineConfiguration formEngineConfiguration = new SpringFormEngineConfiguration();
        formEngineConfiguration.setDataSource(dataSource);
        formEngineConfiguration.setTransactionManager(transactionManager);
        formEngineConfiguration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
        //表单引擎配置器
        FormEngineConfigurator formEngineConfigurator = new FormEngineConfigurator();
        formEngineConfigurator.setFormEngineConfiguration(formEngineConfiguration);
        //注册到工作流引擎配置中
        configuration.addConfigurator(formEngineConfigurator);
        //注册自定义表单引擎
        List<FormEngine> customFormEngines = Collections.singletonList(new CustomFormEngine());
        configuration.setCustomFormEngines(customFormEngines);

        //注册自定义行为工厂
        //configuration.setActivityBehaviorFactory(new CustomActivityBehaviorFactory());

        //自定义事件监听器注册
        //if (configuration.getEventDispatcher() == null) {
        //    configuration.setEventDispatcher(new FlowableEventDispatcherImpl());
        //}
        //configuration.getEventDispatcher()
        //        .addEventListener(new TaskUrgingEventListener(), FlowableEngineEventType.CUSTOM);
        //
        /**
         *  校验时机是在流程部署的时候进行验证
         **/
        //自定义流程校验器
        //configuration.setProcessValidator(new CustomProcessValidator());
        //multiTenantDataSourceProcessConfig.buildProcessEngine();

        //自定义流程缓存处理注册
        //configuration.setProcessDefinitionCache(customProcessDeploymentCache);
        //指定流程缓存数量限制
        configuration.setProcessDefinitionCacheLimit(5000);

        //开启异步执行配置
        configuration.setAsyncExecutorActivate(true);

        //注册自定义处理器
        if (configuration.getCustomJobHandlers() == null) {
            configuration.setCustomJobHandlers(ListUtil.list(true));
        }
        configuration.getCustomJobHandlers()
                .add(new TimeoutReminderJobHandler());

        //将自定义日历解析器注册至工作流引擎中
        //configuration.setBusinessCalendarManager(mapBusinessCalendarManager);

        //启用实体链接服务配置
        configuration.setEnableEntityLinks(true);
        //启用流程定义缓存
        configuration.setEnableProcessDefinitionInfoCache(true);
        //自定义ID生成器
        configuration.setIdGenerator(new SnowFlakeIdGenerator());

        /**
         *  开启异步任务全局锁模式，避免多服务情况下的并发冲突问题
         **/
        AsyncJobExecutorConfiguration asyncConfig = new AsyncJobExecutorConfiguration();
        asyncConfig.setGlobalAcquireLockEnabled(true);
        configuration.setAsyncExecutorConfiguration(asyncConfig);

        /**
         *  注册自定义工作任务分发配置
         **/
        //设置异步任务执行模式为消息队列模式
        configuration.setAsyncExecutorMessageQueueMode( true);
        configuration.setJobManager(new RocketMqMessageBasedJobManager());

        /**
         *  异步历史任务配置
         **/
        //启用异步历史任务模式
        configuration.setAsyncHistoryEnabled( true);
        configuration.setAsyncHistoryExecutorActivate( true);
        //启用批量异步历史存储，阈值为3
        configuration.setAsyncHistoryJsonGroupingEnabled( true);
        configuration.setAsyncHistoryJsonGroupingThreshold(3);

        AsyncJobExecutorConfiguration jobConf = new AsyncJobExecutorConfiguration();
        //设置每批次获取的异步历史任务数
        jobConf.setMaxAsyncJobsDuePerAcquisition(100);
        jobConf.setGlobalAcquireLockEnabled(true);
        configuration.setAsyncHistoryExecutorConfiguration(jobConf);
        //设置异步历史执行线程池的核心线程数和最大线程数
        configuration.setAsyncHistoryExecutorCorePoolSize(20);
        configuration.setAsyncHistoryExecutorMaxPoolSize(20);

        //注册自定义异步历史管理类
        configuration.setHistoryManager(new CustomAsyncHistoryManager(configuration));
        //指定历史流程实例数据处理类
        configuration.setHistoricProcessInstanceDataManager(new MongoHistoricPrecessInstanceDataManager(configuration, mongoTemplate, historicDataCompensationProducer));

        /**
         *  自定义监听器注册配置
         **/
        Map<String, List<FlowableEventListener>> eventListeners = new HashMap<>();
        eventListeners.put(PROCESS_CREATED.name(), Arrays.asList(processStartListener));
        eventListeners.put(TASK_CREATED.name(), Arrays.asList(taskCreateListener));
        configuration.setTypedEventListeners(eventListeners);
        return configuration;
    }

    //@Bean
    //public DynamicBpmnService dynamicBpmnService(ProcessEngine processEngine) {
    //    return processEngine.getDynamicBpmnService();
    //}


    /*
     * <p><b>用途:底层待序列化处理的对象<b></p>
     * @author <a href="mailto:blnp.yibin@qq.com">lyb</a>
     * @since 17:26 2025/6/13
     * @params [] 
     * @param  
     * @return cn.blnp.net.flowable.boot.customer.flowable.cache.FlowableSerializable
    **/
    @SneakyThrows
    public FlowableSerializable flowableSerializable() {
        FlowableSerializable flowableSerializable = new FlowableSerializable();
        flowableSerializable.setSerializableFlowableClassList(
                ListUtil.list(true,
                        "org.flowable.bpmn.model.BpmnModel",
                        "org.flowable.bpmn.model.BaseElement",
                        "org.flowable.bpmn.model.GraphicInfo",
                        "org.flowable.common.engine.impl.event.FlowableEventSupport",
                        "org.flowable.bpmn.model.BpmnDiEdge",
                        "org.flowable.bpmn.model.ExtensionAttribute",
                        "org.flowable.common.engine.impl.persistence.entity.AbstractEntity",
                        "org.flowable.engine.impl.delegate.invocation.DefaultDelegateInterceptor",
                        "org.flowable.common.engine.api.delegate.FlowableFunctionDelegate",
                        "org.flowable.common.engine.impl.el.FlowableAstFunctionCreator"
                )
        );
        flowableSerializable.execute();
        return flowableSerializable;
    }
    
    /** 自定义业务日历配置--start **/

    @Bean
    public DefaultClockImpl defaultClock() {
        //初始化时钟
        return new DefaultClockImpl();
    }

    @Bean
    @DependsOn("defaultClock")
    public CusBusinessCalendar cusBusinessCalendar(DefaultClockImpl clock) {
        //自定义业务日历时钟解析
        return new CusBusinessCalendar(clock);
    }

    @Bean
    @DependsOn("cusBusinessCalendar")
    public MapBusinessCalendarManager mapBusinessCalendarManager(CusBusinessCalendar cusBusinessCalendar) {
        //初始化业务日历管理器
        Map<String, BusinessCalendar> businessCalendars = new HashMap<>();
        //将自定义日历解析器注册至工作流引擎中
        businessCalendars.put(CusBusinessCalendar.NAME, cusBusinessCalendar);
        businessCalendars.put("cycle", cusBusinessCalendar);
        return new MapBusinessCalendarManager(businessCalendars);
    }

    /** 自定义业务日历配置-- End **/
}
